﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows.Data;
using ScrumTable.BL.DM.DataManagement;
using Microsoft.Practices.Unity;
using ScrumTable.Config.ElementManagement;
using ScrumTable.UI.ViewModel.Data;
using ScrumTable.Config.ConfigManagement;
using ScrumTable.UI.ViewModel.Extension;

#endregion

namespace ScrumTable.UI.ViewModel
{
    /// <summary>
    /// Description of the class
    /// </summary>
    public abstract class DynamicUiBase : ViewModelBase
    {

        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------
        private ScrumViewModelData _scrumData;
        private readonly List<ICollectionView> _views = new List<ICollectionView>(5);

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------  


        /// <summary>
        /// Gets or sets the config manager.
        /// </summary>
        /// <value>The config manager.</value>
        [Dependency]
        public ConfigManager ConfigManager { get; set; }

        /// <summary>
        /// Gets or sets the scrum data.
        /// </summary>
        /// <value>The scrum data.</value>
        [Dependency]
        public ScrumViewModelData ScrumData
        {
            get
            {
                return _scrumData;
            }
            set
            {
                _scrumData = value;

                ScrumData.DataContext.ElementChanged += OnContextElementChanged;
                ScrumData.DataContext.CollectionChanged += OnContextCollectionChanged;
                ScrumData.PropertyChanged += OnScrumDataPropertyChanged;
            }
        }

 
        /// <summary>
        /// List of task in the ToDoState
        /// </summary>
        /// <value>List of task in the ToDoState</value>
        public abstract ObservableCollection<IScrumItemViewModel<DomainBase>>[] Collections { get; }

        public abstract IEnumerable<ScrumState> States { get; }

        public virtual TargetConfig Config { get; set;}

         
        #endregion

        /// <summary>
        /// Moves the items in the current list.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <param name="listTasks">The list tasks.</param>
        /// <param name="scrumData">The scrum data.</param>
        /// <param name="whereClause"></param>
        /// <returns></returns>
        protected ObservableCollection<IScrumItemViewModel<DomainBase>> SetTaskOnList(ScrumState state, ref ObservableCollection<IScrumItemViewModel<DomainBase>> listTasks, ScrumViewModelData scrumData, Predicate<ScrumItemBase> whereClause = null)
        {
            List<IScrumItemViewModel<DomainBase>> items = new List<IScrumItemViewModel<DomainBase>>();
            if(Config.IsBug)
            {
                if (Config.IsStory)
                {
                    items.AddRange(SelectBugByStateAsUserStory(state, whereClause));
                    if(Config.IsTask)
                    {
                        items.AddRange(SelectBugByState(state, whereClause));
                    }
                }
                else
                {
                    items.AddRange(SelectBugByState(state, whereClause));
                }
            }
            if (Config.IsStory)
            {
                items.AddRange(SelectStoryByState(state, whereClause));
                SelectBugByState(state);
            }
            if (Config.IsTask)
            {
                items.AddRange(SelectTasksByState(state, whereClause));
            }
            
            if (listTasks == null)
            {
                listTasks = new ObservableCollection<IScrumItemViewModel<DomainBase>>(items);
                var listView = CollectionViewSource.GetDefaultView(listTasks);
                listView.Filter = listView.Filter = new Predicate<object>(Filter);
                _views.Add(listView);
            }
            else
            {
                listTasks.UnionToLeft(new ObservableCollection<IScrumItemViewModel<DomainBase>>(items));
            }

            listTasks.SortDomainItems();
            return listTasks;
        }
    
        private bool Filter(object item)
        {
            return _scrumData.ContainsFilter(item);
        }

        public IEnumerable<IScrumItemViewModel<DomainBase>> SelectTasksByState(ScrumState state, Predicate<ScrumItemBase> predicate = null)
        {
            predicate = GetDefaultWherePredicate(predicate);
            var items = from x in ScrumData.CurrentIteration.Stories
                        from y in x.Tasks
                        where y.State == state && predicate(y)
                        select (IScrumItemViewModel<DomainBase>)new TaskViewModel(y);
            return items;
        }

        public IEnumerable<IScrumItemViewModel<DomainBase>> SelectStoryByState(ScrumState state, Predicate<ScrumItemBase> predicate = null)
        {
            predicate = GetDefaultWherePredicate(predicate);
            var items = from x in ScrumData.CurrentIteration.Stories
                        where x.State == state && predicate(x)
                        select (IScrumItemViewModel<DomainBase>)new UserStoryViewModel(x);
            return items;
        }

        public IEnumerable<IScrumItemViewModel<DomainBase>> SelectBugByState(ScrumState state, Predicate<ScrumItemBase> predicate = null)
        {
           predicate = GetDefaultWherePredicate(predicate);
           var items = from x in ScrumData.CurrentIteration.Stories
                       from y in x.Bugs
                       where y.State == state && predicate(y)
                        select (IScrumItemViewModel<DomainBase>)new BugViewModel(y);
            return items;
        }
        
        public IEnumerable<IScrumItemViewModel<DomainBase>> SelectBugByStateAsUserStory(ScrumState state, Predicate<ScrumItemBase> predicate = null)
        {
            predicate = GetDefaultWherePredicate(predicate);

            var items = from x in ScrumData.CurrentIteration.Bugs
                        where x.State == state && predicate(x)
                        select (IScrumItemViewModel<DomainBase>)new BugViewModel(x);
            return items;
        }

        private static Predicate<ScrumItemBase> GetDefaultWherePredicate(Predicate<ScrumItemBase> predicate)
        {
            predicate = predicate ?? (x => true);
            return predicate;
        }

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------
        

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Releases managed (c# or .net) resources.
        /// </summary>
        protected override void ReleaseManagedResources()
        {
            ScrumData.DataContext.ElementChanged -= OnContextElementChanged;
            ScrumData.DataContext.CollectionChanged -= OnContextCollectionChanged;
            ScrumData.PropertyChanged -= new PropertyChangedEventHandler(OnScrumDataPropertyChanged);

            foreach (var view in _views)
            {
                view.Filter = null;
            }

            base.ReleaseManagedResources();
        }

        protected virtual void RefreshLists()
        {
            SendPropertyChanged("Collections");
        }

        #endregion

        #region Events
        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------




        protected virtual void OnContextElementChanged(object sender, PropertyChangedEventArgs e)
        {
        }

        protected virtual void OnContextCollectionChanged(object sender, DomainCollectionChangedEventArgs e)
        {
            RefreshLists();
        }

        protected virtual void OnScrumDataPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Filter" && ScrumData != null)
            {
                foreach (var view in _views)
                {
                    view.Refresh();
                }
            }
            else if (e.PropertyName == "CurrentIteration")
            {
                RefreshLists();
            }
        }



        #endregion
    }
}
